﻿/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mainwindow.h"
#include <QWheelEvent>
#include <QKeyEvent>

#include <QtWidgets>
#include "mymodel.h"
#include <qtableview.h>
#include <QSplitter>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QVXYModelMapper>
#include <QtWidgets/QHeaderView>

using namespace QtCharts;
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QStandardItemModel>
#include <QBarSeries>
#include <QBarSet>
#include <QValueAxis>
#include <QAction>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // 创建界面元素
    splitter = new QSplitter(this);
    leftView = new QTableView(splitter);
    rightView = new QChartView(splitter);
    m_chart = new QChart();
    rightView->setChart(m_chart);

   // columnSelector = new QComboBox(this);
   // connect(columnSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::columnSelected);

    recentFilesMenu = new QMenu("最近文件", this);
    connect(recentFilesMenu, &QMenu::triggered, this, &MainWindow::openRecentFile);

    setCentralWidget(splitter);

    // 创建菜单
    QMenu *fileMenu = menuBar()->addMenu("文件");
    QAction *openAction = fileMenu->addAction("打开");
    connect(openAction, &QAction::triggered, this, &MainWindow::openFile);
    QAction *saveAction = fileMenu->addAction("保存");
    connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
    fileMenu->addMenu(recentFilesMenu); // 将最近文件菜单添加到文件菜单中

    loadRecentFiles(); // 加载最近文件列表
}

MainWindow::~MainWindow()
{
    saveRecentFiles(); // 保存最近文件列表
}

void MainWindow::openFile()
{
    QString filePath = QFileDialog::getOpenFileName(this, "打开CSV文件", "", "CSV文件 (*.csv)");
    if (!filePath.isEmpty()) {
        loadFile(filePath);
        updateRecentFiles(filePath);
    }
}
#if 0
void MainWindow::saveFile()
{
    // 保存文件的逻辑
}

void MainWindow::loadFile(const QString &path)
{
    m_curCsvFile = path;
    QFile file(path);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        QStringList headers = in.readLine().split(',');

        model = new QStandardItemModel(this);
        model->setHorizontalHeaderLabels(headers);

        columnSelector->clear();
        columnSelector->addItems(headers);

        while (!in.atEnd()) {
            QStringList fields = in.readLine().split(',');
            QList<QStandardItem*> items;
            for (const QString &field : fields) {
                items.append(new QStandardItem(field));
            }
            model->appendRow(items);
        }

        leftView->setModel(model);

        // 初始显示第一列
        columnSelected(0);
    }
}
void MainWindow::columnSelected(int index)
{
    m_chart->removeAllSeries();
    QBarSeries *series = new QBarSeries();
    QBarSet *set = new QBarSet(model->horizontalHeaderItem(index)->text());

    for (int row = 0; row < model->rowCount(); ++row) {
        QModelIndex index = model->index(row, index);
        *set << index.data().toDouble();
    }

    series->append(set);
    m_chart->addSeries(series);

    QValueAxis *axisY = new QValueAxis();
    m_chart->addAxis(axisY, Qt::AlignLeft);
    series->attachAxis(axisY);

    QValueAxis *axisX = new QValueAxis();
    m_chart->addAxis(axisX, Qt::AlignBottom);
    series->attachAxis(axisX);
}
#endif

void MainWindow::updateRecentFiles(const QString &path)
{
    recentFiles.removeAll(path);
    recentFiles.prepend(path);
    if (recentFiles.size() > 5) {
        recentFiles.removeLast();
    }

    recentFilesMenu->clear();
    for (const QString &file : recentFiles) {
        QAction *action = recentFilesMenu->addAction(file);
    }
}

void MainWindow::saveRecentFiles()
{
    QSettings settings("settings.ini", QSettings::IniFormat);
    settings.beginWriteArray("recentFiles");
    for (int i = 0; i < recentFiles.size(); ++i) {
        settings.setArrayIndex(i);
        settings.setValue("path", recentFiles[i]);
    }
    settings.endArray();
}

void MainWindow::loadRecentFiles()
{
    QSettings settings("settings.ini", QSettings::IniFormat);
    int size = settings.beginReadArray("recentFiles");
    for (int i = 0; i < size; ++i) {
        settings.setArrayIndex(i);
        QString path = settings.value("path").toString();
        if (!path.isEmpty()) {
            recentFiles.append(path);
        }
    }
    settings.endArray();

    recentFilesMenu->clear();
    for (const QString &file : recentFiles) {
        QAction *action = recentFilesMenu->addAction(file);
        connect(action, &QAction::triggered, this, &MainWindow::openRecentFile);
    }
}

void MainWindow::openRecentFile()
{
    QAction *action = qobject_cast<QAction*>(sender());
    if (action) {
        QString filePath = action->text();
        loadFile(filePath);
        updateRecentFiles(filePath);
    }
}


void MainWindow::saveFile()
{
    if (m_curCsvFile.isEmpty())
        return;
    QFileInfo fileinfo(m_curCsvFile);
    QString  file_name = fileinfo.baseName();
    QString  file_suffix = fileinfo.suffix();
    QString  file_path = fileinfo.absolutePath();
    QDir dir(fileinfo.canonicalPath());
    QString subDataPath = dir.absoluteFilePath(file_name);
    if (QFileInfo::exists(subDataPath))
    {
        QFileInfo dirinfo(subDataPath);
        if (!dirinfo.isDir()) {
            qDebug() << "error->" << subDataPath << " exist,but not a dir";
            return;
        }
    }
    else {
        QDir dir;
        if (!dir.mkpath(subDataPath))
        {
            qDebug() << "error->create path" << subDataPath << " error";
            return;
        }
    }
    int t[] = { 1,3,5,10,15,30,60,120,240,0 };
    //int t[] = { 3,0 };
    for (int* p = t; *p; p++) {
        QDir dir(subDataPath);
        QString fileName = file_name + QString("_%1.csv").arg(*p);
        QString absFilePath = dir.absoluteFilePath(fileName);
        model->saveVibrateCSVFile(absFilePath, *p);
    }
}

// 提取公共部分为函数
QList<int> MainWindow::showColumnSelectionDialog()
{
    // 获取列标题
    QStringList headers;
    for (int i = 1; i < model->columnCount(); ++i) {
        headers.append(model->getColName(i));
    }

    // 创建选择对话框
    QDialog dialog(this);
    dialog.setWindowTitle("选择要显示的列");
    QVBoxLayout *layout = new QVBoxLayout(&dialog);
    QListWidget *listWidget = new QListWidget(&dialog);
    for (const QString &header : headers) {
        QListWidgetItem *item = new QListWidgetItem(header);
        item->setCheckState(Qt::Unchecked);
        listWidget->addItem(item);
    }

    // 恢复之前的选择状态
    for (auto series : m_chart->series()) {
        QString seriesName = series->name();
        for (int i = 0; i < listWidget->count(); ++i) {
            if (listWidget->item(i)->text() == seriesName) {
                listWidget->item(i)->setCheckState(Qt::Checked);
                break;
            }
        }
    }

    layout->addWidget(listWidget);

    QPushButton *okButton = new QPushButton("确认", &dialog);
    connect(okButton, &QPushButton::clicked, &dialog, &QDialog::accept);
    layout->addWidget(okButton);

    // 显示对话框
    QList<int> selectedColumns;
    if (dialog.exec() == QDialog::Accepted) {
        for (int i = 0; i < listWidget->count(); ++i) {
            if (listWidget->item(i)->checkState() == Qt::Checked) {
                selectedColumns.append(i + 1);
            }
        }
    }
    return selectedColumns;
}

void MainWindow::loadFile(const QString &fileName)
{
    if (splitter == nullptr)
    {
        splitter = new QSplitter(this);
        leftView = new QTableView(this);
        rightView = new QChartView(this);
        splitter->addWidget(leftView);
        splitter->addWidget(rightView);
        splitter->setStretchFactor(0, 0);
        splitter->setStretchFactor(1, 1);
        this->setCentralWidget(splitter);
        m_chart = new QChart;
        rightView->setChart(m_chart);
        m_chart->setAnimationOptions(QChart::NoAnimation);


        QDesktopWidget* desktopWidget = QApplication::desktop();
        QRect deskRect = desktopWidget->availableGeometry();
        int width = deskRect.width() / 2;
        QList<int> list;
        list.push_back(width);
        list.push_back(width);
        splitter->setSizes(list);
    }

    model = new MyModel(leftView);

    if (model->openfile((char*)fileName.toStdString().c_str()))
    {
        delete model;
        return;
    }
    m_curCsvFile = fileName;
    leftView->setModel(model);

    QList<int> selectedColumns = showColumnSelectionDialog();
    if (!selectedColumns.isEmpty()) {
        m_chart->removeAllSeries();
        regenerateChart(selectedColumns);
    }

    QItemSelectionModel *selectionModel = new QItemSelectionModel(model);
    leftView->setSelectionModel(selectionModel);

#if 0
    leftView->setColumnWidth(0, 300);
    for (int i = 1; i < model->columnCount(); i++) {
        leftView->setColumnWidth(i, 120);
    }
#endif
    leftView->verticalHeader()->show();
    leftView->show();
    splitter->show();

    statusBar()->showMessage(tr("Loaded %1").arg(fileName), 2000);
    QFileInfo fileinfo(m_curCsvFile);
    QString  file_name = fileinfo.baseName();
    setWindowTitle(tr("Data Analysis")+"-" + file_name);
    rightView->installEventFilter(this); // 为 QChartView 安装事件过滤器
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == rightView && event->type() == QEvent::Wheel) {

        QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
        bool ctrlPressed = wheelEvent->modifiers() & Qt::ControlModifier;

        // 确保轴是具体的轴类实例
        QValueAxis *axisX = qobject_cast<QValueAxis*>(m_chart->axisX());
        QValueAxis *axisY = qobject_cast<QValueAxis*>(m_chart->axisY());

        if (axisX && axisY) {
            qreal scaleFactor = wheelEvent->angleDelta().y() > 0 ? 1.1 : 0.9;
            if (ctrlPressed) {
                // Ctrl + 鼠标滚轮，对 y 轴进行缩放
                qreal minY = axisY->min();
                qreal maxY = axisY->max();
                qreal centerY = (minY + maxY) / 2;
                qreal newRangeY = (maxY - minY) / scaleFactor;
                axisY->setRange(centerY - newRangeY / 2, centerY + newRangeY / 2);
            } else {
                // 普通鼠标滚轮，对 x 轴进行缩放
                qreal minX = axisX->min();
                qreal maxX = axisX->max();
                qreal centerX = (minX + maxX) / 2;
                qreal newRangeX = (maxX - minX) / scaleFactor;
                axisX->setRange(centerX - newRangeX / 2, centerX + newRangeX / 2);
            }
            return true;
        }
    }
    return QMainWindow::eventFilter(obj, event);
}

void MainWindow::regenerateChart(const QList<int>& selectedColumns)
{
    m_chart->removeAllSeries();

    for (int columnIndex : selectedColumns) {
        QLineSeries* series = new QLineSeries;
        series->setName(model->getColName(columnIndex));
        QVXYModelMapper* mapper = new QVXYModelMapper(m_chart);
        mapper->setXColumn(0);
        mapper->setYColumn(columnIndex);
        mapper->setSeries(series);
        mapper->setModel(model);
        m_chart->addSeries(series);
    }
    m_chart->createDefaultAxes();
}
